﻿-------------------------------------------------------------------------------
-- Addon - Health - Init
-------------------------------------------------------------------------------
-- Version
local MAJOR = "Avion2_Health"
local MINOR = tonumber(("@project-revision@"):match("%d+")) or 0

-- Dependencies
if not Avion2Core 				then error(MAJOR .. " requires Avion2.") end
if not LibStub("AceEvent-3.0")	then error(MAJOR .. " requires AceEvent-3.0.") end

-- Create
Avion2_Health 			= Avion2Core:NewModule(MAJOR, "AceEvent-3.0")
Avion2_Health.major 	= MAJOR
Avion2_Health.minor 	= MINOR


-------------------------------------------------------------------------------
-- Addon - Health - Variables
-------------------------------------------------------------------------------
-- Translation
local L 	= LibStub("AceLocale-3.0"):GetLocale(MAJOR)
local coreL	= LibStub("AceLocale-3.0"):GetLocale(Avion2Core.major)

-- Local functions
local HealthUpdate


-------------------------------------------------------------------------------
-- Addon - Health - Register with core
-------------------------------------------------------------------------------
-- Register SavedVariables
function Avion2_Health:RegisterModuleDB()
	-- Register own saved variables DB
	self.db = Avion2Core.db:RegisterNamespace(Avion2_Health.major, {
		profile = {
			thresholds 		= {},
			onlyOneActive 	= false,
			lastMinor 		= MINOR,
		},
	})
	
	-- Track last health value
	self.lastPercentage = 100
	
	-- Updateto to new rev, data converters should go here
	self.db.profile.lastMinor = Avion2_Health.minor
end


-- (Un)register (un)needed events
function Avion2_Health:UpdateEventRegistration()
	-- Health events
	if (self:IsEnabled() and next(self.db.profile.thresholds)) then
		self:RegisterEvent("UNIT_HEALTH", HealthUpdate)
	else
		self:UnregisterEvent("UNIT_HEALTH")
	end
end


-- Update animation (convert animationFunc: string name to function pointer)
function Avion2_Health:LoadAnimationTables()
	for _, data in pairs(self.db.profile.thresholds) do
		Avion2Core:LoadAnimationTables(data.animationList)
	end
end


-------------------------------------------------------------------------------
-- Addon - Health - Options
-------------------------------------------------------------------------------
-- Fetch animationTable from animationID (as suplied by eg. Menu_Reuqest)
function Avion2_Health:GetAnimationTable(animationID)
	success, _, arg1, arg2 = self:Deserialize(animationID)
	
	if (success) then
		return self.db.profile.thresholds[arg1].animationList[arg2]
	else
		return false
	end
end


-- Build Optionstable
function Avion2_Health:UpdateOptionTable(args)
	-- Update options when enabled and initialized
	if (self.db and self:IsEnabled()) then
		-- Final options
		args[self.major] = {
			type = 'group',
			name = L["Thresholds"],
			desc = L["Thresholds_Desc"],
			args = {
				new = {
					order = 1,
					type = 'input',
					name = L["NewThreshold"],
					desc = L["NewThreshold_Desc"],
					usage = L["NewThreshold_Usage"],
					pattern = "(%d)",
					get = function()
						return ""
					end,
					set = function(info, val)
						if (not self.db.profile.thresholds[tonumber(val)]) then
							self.db.profile.thresholds[tonumber(val)] = {
								animationList 	= {},
								cancelAnimation	= 0,
							}
							
							Avion2Core:UpdateModuleOptionTable(self)
							self:UpdateEventRegistration()
						end
					end,
				},
				onlyOneActive = {
					order = 2,
					type = 'toggle',
					name = L["OnlyOneActive"],
					desc = L["OnlyOneActive_Desc"],
					get = function()
						return self.db.profile.onlyOneActive
					end,
					set = function()
						self.db.profile.onlyOneActive = not self.db.profile.onlyOneActive
					end,
				},
			},
			icon = self:GetIconPath() .. "Health"
		}
		
		-- Options for each compo-point
		for index, data in pairs(self.db.profile.thresholds) do
			args[self.major].args[string.format("Threshold_%d", index)] = {
				type = 'group',
				name = string.format(L["Threshold"], index),
				desc = string.format(L["Threshold_Desc"], index),
				args = { 
					new = Avion2Core:GetDefaultNewAnimationOption(data.animationList),
					delete = {
						order = 2,
						type = 'execute',
						name = L["DeleteThreshold"],
						desc = L["DeleteThreshold_Desc"],
						func = function()
							Avion2Core:StopAnimationList(string.format("Avion2_HealthThreshold_%d", index), self.db.profile.thresholds[index].animationList, false)
							self.db.profile.thresholds[index] = nil
							
							Avion2Core:UpdateModuleOptionTable(self)
							self:UpdateEventRegistration()
						end,
					},
					cancelAnimation = {
						order = 3,
						type = 'select',
						name = coreL["CancelAnimation"],
						desc = coreL["CancelAnimation_Desc"],
						values = {
							[0] = coreL["DontCancel"],
							[1] = coreL["FadeOut"],
							[2] = coreL["Cancel"],
						},
						get = function()
							return data.cancelAnimation
						end,
						set = function(info, val)
							data.cancelAnimation = val
						end,
					},
				},
			}
			-- Add options for each animation
			for animationListID, _ in pairs(data.animationList) do
				-- Combine all info to find this animation in module db in ONE string
				local serializedInfo = self:Serialize(Avion2_Health.major, index, animationListID)
				
				-- Update option table
				args[self.major].args[string.format("Threshold_%d", index)].args[string.format("Animation_%d", animationListID)] = Avion2Core:GetDefaultAnimationOption(data.animationList, animationListID, serializedInfo)
			end
		end

	-- Disabled, remove options
	else
		args[self.major] = nil
	end
end


-------------------------------------------------------------------------------
-- Addon - Health - Events
-------------------------------------------------------------------------------
-- Create here, so we don't have to create locals on every call of UNIT_*
local currentPercentage, lowestThreshold


-- Health changed
HealthUpdate = function(eventName, unitID)
	-- Track only for player
	if (unitID == "player") then	
		-- Save current health
		currentPercentage 	= UnitHealth("player") / UnitHealthMax("player") * 100
		lowestThreshold 	= -1
		
		-- For each threshold, trigger all animation since last update and cancel all old one
		for threshold, data in pairs(Avion2_Health.db.profile.thresholds) do
			-- Check if health if greater than threshold
			if (Avion2_Health.db.profile.onlyOneActive or Avion2_Health.db.profile.thresholds[threshold].cancelAnimation ~= 0 and currentPercentage > threshold) then -- and threshold >= self.lastPercentage
				Avion2Core:StopAnimationList(string.format("Avion2_HealthThreshold_%d", index), Avion2_Health.db.profile.thresholds[threshold].animationList, (not Avion2_Health.db.profile.onlyOneActive and Avion2_Health.db.profile.thresholds[threshold].cancelAnimation == 1))
			end

			-- Check if health is inside interval [newHealth - oldHealth)
			if (currentPercentage <= threshold and threshold < Avion2_Health.lastPercentage) then
				-- If onlyOneActive is set, keep track of loewst thresthold (if available) and don't fire an animation (yet)
				if (Avion2_Health.db.profile.onlyOneActive) then
					if (threshold < lowestThreshold or lowestThreshold == -1) then
						lowestThreshold = threshold
					end
				else
					Avion2Core:TriggerAnimationList(string.format("Avion2_HealthThreshold_%d", threshold), Avion2_Health.db.profile.thresholds[threshold].animationList)
				end
			end
		end
		
		-- When onlyOneActive is set, than lowestThreshold is updated until lowest threshold is found
		if (Avion2_Health.db.profile.onlyOneActive and Avion2_Health.db.profile.thresholds[lowestThreshold]) then
			Avion2Core:TriggerAnimationList(string.format("Avion2_HealthThreshold_%d", threshold), Avion2_Health.db.profile.thresholds[lowestThreshold].animationList)
		end
		
		-- Update current/last health
		Avion2_Health.lastPercentage = currentPercentage
	end
end
